﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SSharp.Core.DataTypes {
	/// <summary>
	/// A symbol is basically an interned string. It is a different data type in Scheme though.
	/// </summary>
	public class Symbol {
		private readonly string Value;

		public Symbol(string value) {
			if (value == null) {
				// empty symbols are valid - but not null ones
				throw new ArgumentNullException("Invalid Symbol value: null");
			}

			this.Value = string.Intern(value);
		}

		public override bool Equals(object obj) {
			if (ReferenceEquals(obj, null)) {
				return false;
			}
			if (!(obj is Symbol)) {
				return false;
			}

			// we can check ReferenceEquals, which is quicker than string comparison, because we interened the string in the constructor.
			return ReferenceEquals(Value, ((Symbol)obj).Value);
		}

		public override int GetHashCode() {
			return Value.GetHashCode();
		}

		public override string ToString() {
			return Value;
		}

		public static bool operator ==(Symbol left, Symbol right) {
			if (ReferenceEquals(left, null)) {
				return ReferenceEquals(right, null);
			} else {
				return left.Equals(right);
			}
		}

		public static bool operator !=(Symbol left, Symbol right) {
			return !(left == right);
		}

		public static implicit operator string(Symbol symbol) {
			if (symbol == null) {
				return null;
			} else {
				return symbol.Value;
			}
		}

		public static explicit operator Symbol(string value) {
			return new Symbol(value);
		}
	}
}
